/// @file task_scheduler.h
/// @brief 简单的任务调度器，支持一次性和周期性任务，提供全局单例访问

#ifndef __UTOOLS_TASK_SCHEDULER_H__
#define __UTOOLS_TASK_SCHEDULER_H__

#include "../utools_cfg.h"

#if UTOOLS_COLLAB_TASK_SCHEDULER_ENABLE == UTOOLS_TRUE

#include <functional>
#include <chrono>
#include <cstdint>
#include <map>
#include <vector>
#include <mutex>
#include <thread>
#include <atomic>
#include <condition_variable>

namespace utools::collab
{
    using TaskId = uint64_t;

    class TaskScheduler
    {
    public:
        TaskScheduler()
        {
            __next_id = 1;
        }

        ~TaskScheduler()
        {
            stop_loop();
            clear();
        }

        // non-copy
        TaskScheduler(const TaskScheduler &) = delete;
        TaskScheduler &operator=(const TaskScheduler &) = delete;

        // 添加一个周期性任务，接受任何可调用对象及 std::chrono::duration
        template <typename F, typename Rep, typename Period>
        TaskId add_periodic(F &&cb, const std::chrono::duration<Rep, Period> &interval)
        {
            std::function<void()> f = std::forward<F>(cb);
            if (!f)
                return 0;
            std::lock_guard<std::mutex> lk(__mtx);
            Task t;
            t.id = __next_id++;
            t.cb = std::move(f);
            t.interval = std::chrono::duration_cast<std::chrono::steady_clock::duration>(interval);
            t.repeat = true;
            t.next_run = std::chrono::steady_clock::now() + t.interval;
            __tasks.emplace(t.id, std::move(t));
            __cv.notify_one();
            return t.id;
        }

        // 添加一个周期性任务，接受 std::function<void()>
        TaskId add_periodic(std::function<void()> cb, std::chrono::milliseconds interval)
        {
            return add_periodic<std::function<void()>, std::chrono::milliseconds::rep, std::chrono::milliseconds::period>(std::move(cb), interval);
        }

        // 添加周期性任务：接受可调用对象并绑定额外参数（比如 free function 或 functor + args）
        template <typename F, typename... Args, typename Rep, typename Period>
        TaskId add_periodic(F &&f, const std::chrono::duration<Rep, Period> &interval, Args &&...args)
        {
            auto bound = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
            return add_periodic(std::move(bound), interval);
        }

        // 添加周期性任务：成员函数 (Obj, &Obj::method)
        template <typename Obj, typename MemFn, typename Rep, typename Period>
        TaskId add_periodic(Obj *obj, MemFn memfn, const std::chrono::duration<Rep, Period> &interval)
        {
            if (!obj || !memfn)
                return 0;
            auto cb = [obj, memfn]()
            { (obj->*memfn)(); };
            return add_periodic(cb, interval);
        }

        template <typename Obj, typename MemFn, typename Rep, typename Period>
        TaskId add_periodic(Obj &obj, MemFn memfn, const std::chrono::duration<Rep, Period> &interval)
        {
            auto cb = [&obj, memfn]()
            { (obj.*memfn)(); };
            return add_periodic(cb, interval);
        }

        // 添加一次性任务（delay），接受 callable + chrono duration
        template <typename F, typename Rep, typename Period>
        TaskId add_one_shot(F &&cb, const std::chrono::duration<Rep, Period> &delay)
        {
            std::function<void()> f = std::forward<F>(cb);
            if (!f)
                return 0;
            std::lock_guard<std::mutex> lk(__mtx);
            Task t;
            t.id = __next_id++;
            t.cb = std::move(f);
            t.interval = std::chrono::duration_cast<std::chrono::steady_clock::duration>(delay);
            t.repeat = false;
            t.next_run = std::chrono::steady_clock::now() + t.interval;
            __tasks.emplace(t.id, std::move(t));
            __cv.notify_one();
            return t.id;
        }

        // 添加一次性任务，接受 std::function<void()>
        TaskId add_one_shot(std::function<void()> cb, std::chrono::milliseconds delay)
        {
            return add_one_shot<std::function<void()>, std::chrono::milliseconds::rep, std::chrono::milliseconds::period>(std::move(cb), delay);
        }

        // 添加一次性任务：接受可调用对象并绑定额外参数
        template <typename F, typename... Args, typename Rep, typename Period>
        TaskId add_one_shot(F &&f, const std::chrono::duration<Rep, Period> &delay, Args &&...args)
        {
            auto bound = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
            return add_one_shot(std::move(bound), delay);
        }

        // 添加一次性任务：成员函数 (Obj, &Obj::method)
        template <typename Obj, typename MemFn, typename Rep, typename Period>
        TaskId add_one_shot(Obj *obj, MemFn memfn, const std::chrono::duration<Rep, Period> &delay)
        {
            if (!obj || !memfn)
                return 0;
            auto cb = [obj, memfn]()
            { (obj->*memfn)(); };
            return add_one_shot(cb, delay);
        }

        template <typename Obj, typename MemFn, typename Rep, typename Period>
        TaskId add_one_shot(Obj &obj, MemFn memfn, const std::chrono::duration<Rep, Period> &delay)
        {
            auto cb = [&obj, memfn]()
            { (obj.*memfn)(); };
            return add_one_shot(cb, delay);
        }

        // 移除任务，成功返回 true
        bool remove(TaskId id)
        {
            std::lock_guard<std::mutex> lk(__mtx);
            auto it = __tasks.find(id);
            if (it != __tasks.end())
            {
                __tasks.erase(it);
                __cv.notify_one();
                return true;
            }
            return false;
        }

        // 清空所有任务
        void clear()
        {
            std::lock_guard<std::mutex> lk(__mtx);
            __tasks.clear();
            __cv.notify_one();
        }

        /// @brief 执行所有到期任务（由调用方循环或其它线程调用）。
        void run_pending()
        {
            std::vector<Task> due;
            {
                std::lock_guard<std::mutex> lk(__mtx);
                auto now = std::chrono::steady_clock::now();
                for (auto it = __tasks.begin(); it != __tasks.end();)
                {
                    if (!it->second.enabled)
                    {
                        ++it;
                        continue;
                    }
                    if (it->second.next_run <= now)
                    {
                        due.push_back(it->second);
                        if (it->second.repeat)
                        {
                            it->second.next_run = now + it->second.interval;
                            ++it;
                        }
                        else
                        {
                            it = __tasks.erase(it);
                        }
                    }
                    else
                    {
                        ++it;
                    }
                }
            }

            for (auto &t : due)
            {
                try
                {
                    if (t.cb)
                        t.cb();
                }
                catch (...)
                {
                }
            }
        }

        /// @brief 启动调度 loop 线程
        void start_loop()
        {
            if (__loop_run.load())
                return;
            __loop_run.store(true);
            __loop_thread = std::thread([this]()
                                        {
                std::unique_lock<std::mutex> lk(this->__mtx);
                while (this->__loop_run.load())
                {
                    if (this->__tasks.empty())
                    {
                        this->__cv.wait(lk);
                        continue;
                    }

                    auto now = std::chrono::steady_clock::now();
                    auto earliest = std::chrono::steady_clock::time_point::max();
                    for (const auto &p : this->__tasks)
                    {
                        if (!p.second.enabled)
                            continue;
                        if (p.second.next_run < earliest)
                            earliest = p.second.next_run;
                    }

                    if (earliest == std::chrono::steady_clock::time_point::max())
                    {
                        this->__cv.wait(lk);
                        continue;
                    }

                    if (earliest <= now)
                    {
                        lk.unlock();
                        this->run_pending();
                        lk.lock();
                        continue;
                    }

                    this->__cv.wait_until(lk, earliest);
                }

                lk.unlock();
                this->run_pending(); });
        }

        /// @brief 停止调度 loop 线程
        void stop_loop()
        {
            if (!__loop_run.load())
                return;
            __loop_run.store(false);
            __cv.notify_all();
            if (__loop_thread.joinable())
                __loop_thread.join();
        }

        /// @brief 查询任务数
        /// @return 任务数量
        size_t task_count() const
        {
            std::lock_guard<std::mutex> lk(__mtx);
            return __tasks.size();
        }

    private:
        struct Task
        {
            TaskId id{0};
            std::function<void()> cb;
            std::chrono::steady_clock::duration interval{0};
            bool repeat{false};
            std::chrono::steady_clock::time_point next_run;
            bool enabled{true};
        };

        mutable std::mutex __mtx;
        std::map<TaskId, Task> __tasks;
        TaskId __next_id{1};

        std::thread __loop_thread;
        std::atomic<bool> __loop_run{false};
        std::condition_variable __cv;
    };

} // namespace utools::collab

#endif // UTOOLS_COLLAB_TASK_SCHEDULER_ENABLE

#endif // __UTOOLS_TASK_SCHEDULER_H__
